home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / utilities / printer / post-1.6src.lzh / postchar.c < prev    next >
C/C++ Source or Header  |  1991-04-17  |  38KB  |  1,204 lines

  1. /* PostScript interpreter file "postchar.c" - character routines */
  2. /* (C) Adrian Aylward 1989, 1991 */
  3.  
  4. # include "post.h"
  5.  
  6. /* Routines */
  7.  
  8. extern void cachefast(struct fcrec *pfcrec,
  9.                       int xpos1, int ypos1, int y1, int y2);
  10. extern void cacheslow(struct fcrec *pfcrec,
  11.                       int xpos1, int ypos1, int y1, int y2);
  12.  
  13. /* Initialise the character routines */
  14.  
  15. void initchar(void)
  16. {   struct object token, *aptr;
  17.     char *s;
  18.     int i;
  19.  
  20.     /* Create various names for character operations */
  21.  
  22.     for (i = 0; i < charmax; i++)
  23.         nametoken(&charname[i], chartable[i], -1, 0);
  24.  
  25.     /* Create the standard encoding vector */
  26.  
  27.     token.type = typearray;
  28.     token.flags = 0;
  29.     token.length = 256;
  30.     token.value.vref = arrayalloc(256);
  31.     aptr = vmaptr(token.value.vref);
  32.     for (i = 0; i < 256; i++)
  33.     {   s = ((i & 0x60) == 0) ? NULL :
  34.                                 stdentable[i - ((i < 0x80) ? 0x20 : 0x40)];
  35.         if (s)
  36.             nametoken(&aptr[i], s, -1, 0);
  37.         else
  38.             aptr[i] = charname[charnotdef];
  39.     }
  40.     dictput(dictstack[0].value.vref, &charname[charstdencoding], &token);
  41.     stdencoding = aptr;
  42.  
  43.     /* Create the font directorary */
  44.  
  45.     dicttoken(&fontdir, fontdictsize);
  46.     dictput(dictstack[0].value.vref, &charname[charfontdirectory], &fontdir);
  47.  
  48.     /* Initialise the font cache */
  49.  
  50.     fmcount = 0;
  51.     fmcache = vmallocv(sizeof (struct fmrec) * fmsize);
  52.     fccache = vmallocv(sizeof (struct fcrec *) * fcsize);
  53.     fcptr = fcbeg = memfbeg;
  54.     fcend = (struct fcrec *) ((char *) memfbeg + memflen);
  55.     fclen = memflen;
  56.     if (fclen < sizeof (struct fcrec))
  57.         fclen = 0;
  58.     else
  59.     {   fcbeg->reclen = fclen;
  60.         fcbeg->count = 0;
  61.     }
  62.     istate.fclim = fclen;
  63.     fclimit = fclen / 40;
  64.  
  65.     /* Initialise the current font */
  66.  
  67.     token.type = 0;
  68.     token.flags = 0;
  69.     token.length = 0;
  70.     token.value.ival = 0;
  71.     gstate.font = token; 
  72.  
  73.     /* Initialise type 1 fonts */
  74.  
  75.     initfont();
  76. }
  77.  
  78. /* Restore the font cache */
  79.  
  80. void vmrestfont(struct vmframe *vmframe)
  81. {   struct fmrec *pfmrec;
  82.     struct fcrec *pfcrec, *pfcnxt, **ppfcrec;
  83.     int i;
  84.  
  85.     /* Scan the make cache to purge entries more recent than the vm save */
  86.  
  87.     pfmrec = &fmcache[0];
  88.     i = fmsize;
  89.     while (i--)
  90.     {   if (pfmrec->id != 0)
  91.             if (vmscheck(vmframe, pfmrec->dref)) pfmrec->id = 0;
  92.         pfmrec++;
  93.     }
  94.  
  95.     /* Scan the character cache, purging entries from the hash chains */
  96.  
  97.     if (fclen == 0) return;
  98.  
  99.     for (i = 0; i < fcsize; i++)
  100.     {   ppfcrec = &fccache[i];
  101.         for (;;)
  102.         {   pfcrec = *ppfcrec;
  103.             if (pfcrec == NULL) break;
  104.             if (vmscheck(vmframe, pfcrec->nref) ||
  105.                 vmscheck(vmframe, pfcrec->dref))
  106.             {   *ppfcrec = pfcrec->chain;
  107.                 pfcrec->count = 0;
  108.             }
  109.             else
  110.                 ppfcrec = &pfcrec->chain;
  111.         }
  112.     }
  113.  
  114.     /* Scan the character cache, joining adjacent free records */
  115.  
  116.     pfcrec = fcbeg;
  117.     while (pfcrec != fcend)
  118.     {   if (pfcrec->count == 0)
  119.         {   pfcnxt = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  120.             if (pfcnxt != fcend && pfcnxt->count == 0)
  121.             {   if (fcptr == pfcnxt) fcptr = pfcrec;
  122.                 pfcrec->reclen += pfcnxt->reclen;
  123.             }
  124.         }
  125.         pfcrec = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  126.     }
  127. }
  128.  
  129. /* Define a font */
  130.  
  131. void definefont(struct object *key, struct object *font)
  132. {   struct object token;
  133.  
  134.     /* Validate the font.  Get the uniqe id if we have one and construct
  135.      * the font id */
  136.  
  137.     checkfont(font, 0);
  138.     fontid = 0;
  139.     if (dictget(font->value.vref, &charname[charuniqueid], &token, 0))
  140.     {   if (token.type != typeint || (token.value.ival & 0xff000000) != 0)
  141.             error(errinvalidfont);
  142.         fontid = (fonttype << 24) | token.value.ival;
  143.     }
  144.     token.type = typefont;
  145.     token.flags = 0;
  146.     token.length = 0;
  147.     token.value.ival = fontid;
  148.     dictput(font->value.vref, &charname[charfid], &token);
  149.  
  150.     /* Make it read only and insert it into the font directory */
  151.  
  152.     vmdptr(font->value.vref)->flags |= flagwprot;
  153.     dictput(fontdir.value.vref, key, font);
  154. }
  155.  
  156. /* Find a font */
  157.  
  158. void findfont(struct object *key, struct object *font)
  159. {   if (!dictget(fontdir.value.vref, key, font, 0)) error(errinvalidfont);
  160. }
  161.  
  162. /* Make a font */
  163.  
  164. void makefont(struct object *font, float *matrix)
  165. {   struct object token;
  166.     struct dictionary *odict, *ndict;
  167.     struct fmrec *pfmrec, *pfmrcu;
  168.     vmref ndref;
  169.     float oldmatrix[6], newmatrix[6];
  170.     int count, i;
  171.  
  172.     /* Validate the font and calculate the new matrix */
  173.  
  174.     checkfont(font, 1);
  175.     getmatrix(fontmatrix, oldmatrix);
  176.     multiplymatrix(newmatrix, oldmatrix, matrix);
  177.  
  178.     /* Look in the make cache to see if we have made one like this before.
  179.      * We only cache fonts that have unique ids.  If we find one update the
  180.      * usage counter on its cache record */
  181.  
  182.     fmcount++;
  183.     if (fontid != 0)
  184.     {   pfmrec = &fmcache[0];
  185.         i = fmsize;
  186.         while (i--)
  187.         {   if (pfmrec->id == fontid &&
  188.                 pfmrec->encodlen == fontencodlen &&
  189.                 pfmrec->encoding == fontencoding &&
  190.                 memcmp((char *) pfmrec->matrix,
  191.                        (char *) newmatrix, sizeof newmatrix) == 0)
  192.             {   pfmrec->count = fmcount;
  193.                 font->value.vref = pfmrec->dref;
  194.                 return;
  195.             }
  196.             pfmrec++;
  197.         }
  198.     }
  199.  
  200.     /* Copy the font.  Replace the matrix with the new one */
  201.  
  202.     odict = vmdptr(font->value.vref);
  203.     ndref = vmalloc(odict->length);
  204.     ndict = vmdptr(ndref);
  205.     memcpy((char *) ndict, (char *) odict, odict->length);
  206.     ndict->saved = vmnest;
  207.     ndict->flags &= ~flagwprot;
  208.     fontmatrix = arrayalloc(6);
  209.     token.type = typearray;
  210.     token.flags = 0;
  211.     token.length = 6;
  212.     token.value.vref = fontmatrix;
  213.     putmatrix(fontmatrix, newmatrix);
  214.     dictput(ndref, &charname[charfontmatrix], &token);
  215.     ndict->flags |= flagwprot;
  216.     font->value.vref = ndref;
  217.  
  218.     /* Save the new font in the cache.  Look for an empty slot; if we don't
  219.      * find one use the least recently used */
  220.  
  221.     if (fontid != 0)
  222.     {   pfmrcu = pfmrec = &fmcache[0];
  223.         i = fmsize;
  224.         count = 0x7fffffff;
  225.         while (i--)
  226.         {   if (pfmrec->count < count)
  227.             {   count = pfmrec->count;
  228.                 pfmrcu = pfmrec;
  229.             }
  230.             if (pfmrec->id == 0)
  231.             {   pfmrcu = pfmrec;
  232.                 break;
  233.             }
  234.             pfmrec++;
  235.         }
  236.         pfmrcu->count = fmcount;
  237.         pfmrcu->id = fontid;
  238.         pfmrcu->encodlen = fontencodlen;
  239.         pfmrcu->encoding = fontencoding;
  240.         memcpy((char *) pfmrcu->matrix,
  241.                (char *) newmatrix, sizeof newmatrix);
  242.         pfmrcu->dref = ndref;
  243.     }
  244. }
  245.  
  246. /* Set a font */
  247.  
  248. void setfont(struct object *font)
  249. {   if (font->type != typenull) checkfont(font, 1);
  250.     gstate.font = *font;
  251. }
  252.  
  253. /* Check a font for validity */
  254.  
  255. void checkfont(struct object *font, int fid)
  256. {   struct object token;
  257.     if (font->type != typedict) error(errtypecheck);
  258.     if (!dictget(font->value.vref, &charname[charfonttype], &token, 0))
  259.         error(errinvalidfont);
  260.     if (token.type != typeint ||
  261.         (token.value.ival != 1 && token.value.ival != 3))
  262.         error(errinvalidfont);
  263.     fonttype = token.value.ival;
  264.     if (!dictget(font->value.vref, &charname[charfontmatrix], &token, 0))
  265.         error(errinvalidfont);
  266.     if (token.type != typearray || token.length != 6 ||
  267.         (token.flags & flagrprot))
  268.         error(errinvalidfont);
  269.     fontmatrix = token.value.vref;
  270.     if (!dictget(font->value.vref, &charname[charfontbbox], &token, 0))
  271.         error(errinvalidfont);
  272.     if ((token.type != typearray && token.type != typepacked) ||
  273.         token.length != 4 || (token.flags & flagrprot))
  274.         error(errinvalidfont);
  275.     if (!dictget(font->value.vref, &charname[charencoding], &token, 0))
  276.         error(errinvalidfont);
  277.     if (token.type != typearray || (token.flags & flagrprot))
  278.         error(errinvalidfont);
  279.     fontencodlen = token.length;
  280.     fontencoding = token.value.vref;
  281.     if (dictget(font->value.vref, &charname[charfid], &token, 0) != fid)
  282.         error(errinvalidfont);
  283.     if (fid)
  284.     {   if (token.type != typefont) error(errinvalidfont);
  285.         fontid = token.value.ival;
  286.     }
  287. }
  288.  
  289. /* Show a string (type = 0,1 charpath; 2 stringwidth; 3 show) */
  290.  
  291. void show(struct object *string, int type,
  292.           struct point *width, int wchar, struct object *kproc)
  293. {   struct object token, font, *encoding, bproc;
  294.     struct point cpoint, fpoint;
  295.     struct fcrec fcrec, *pfcrec, **ppfcrec;
  296.     char *sptr;
  297.     float newctm[6], oldctm[6], matrix[6];
  298.     int encodlen, length, schar, iflag, ftype;
  299.     int id, nest, i, lev;
  300.  
  301.     if (istate.flags & intgraph) error(errundefined);
  302.  
  303.     lev = flushlevel(-1);
  304.  
  305.     /* Look up the matrix, encoding, font id */
  306.  
  307.     iflag = 0;
  308.     font = gstate.font;
  309.     if (font.type != typedict) error(errinvalidfont);
  310.     if (!dictget(font.value.vref, &charname[charfontmatrix], &token, 0))
  311.         error(errinvalidfont);
  312.     getmatrix(token.value.vref, matrix);
  313.     if (!dictget(font.value.vref, &charname[charencoding], &token, 0))
  314.         error(errinvalidfont);
  315.     encodlen = token.length;
  316.     encoding = vmaptr(token.value.vref);
  317.     if (!dictget(font.value.vref, &charname[charfid], &token, 0))
  318.         error(errinvalidfont);
  319.     id = token.value.ival;
  320.  
  321.     /* For stringwidth start at zero */
  322.  
  323.     if (type == 2)
  324.     {   cpoint.type = ptmove;
  325.         cpoint.x = cpoint.y = 0.0;
  326.     }
  327.  
  328.     /* Loop for every character in the string */
  329.  
  330.     length = string->length;
  331.     sptr = vmsptr(string->value.vref);
  332.     while (length--)
  333.     {   schar = *((unsigned char *) sptr);
  334.         sptr++;
  335.  
  336.         /* Find the current point */
  337.  
  338.         if (type != 2)
  339.         {   if (gstate.pathend == gstate.pathbeg) error(errnocurrentpoint);
  340.             closepath(ptclosei);
  341.             cpoint = patharray[gstate.pathend - 1];
  342.         }
  343.  
  344.         /* Build the new ctm (current point rounded to pixel boundary) */
  345.  
  346.         memcpy((char *) oldctm, (char *) gstate.ctm, 4 * sizeof (float));
  347.         oldctm[4] = cpoint.x;
  348.         oldctm[5] = cpoint.y;
  349.         multiplymatrix(newctm, matrix, oldctm);
  350.         fpoint.x = newctm[4] = floor(newctm[4] + 0.5);
  351.         fpoint.y = newctm[5] = floor(newctm[5] + 0.5);
  352.  
  353.         /* Don't use the cache for charpath */
  354.  
  355.         fcrec.reclen = 0;
  356.         fcrec.width.x = fcrec.width.y = 0.0;
  357.         if (type < 2) goto nocache;
  358.  
  359.         /* Construct the cache key */
  360.  
  361.         if (schar < encodlen)
  362.         {   token = encoding[schar];
  363.             if (token.type != typename) error(errinvalidfont);
  364.         }
  365.         else
  366.             token = charname[charnotdef];
  367.         fcrec.id = id;
  368.         fcrec.nref = token.value.vref;
  369.         fcrec.dref= (id == 0) ? font.value.vref : 0;
  370.         memcpy((char *) fcrec.matrix, (char *) newctm, 4 * sizeof (float));
  371.         fcrec.hash = id;
  372.         fcrec.hash = fcrec.hash * 12345 + (int) fcrec.dref;
  373.         fcrec.hash = fcrec.hash * 12345 + (int) fcrec.nref;
  374.         for (i = 0; i < 4 ; i++)
  375.             fcrec.hash = fcrec.hash * 12345 + *((int *) &fcrec.matrix[i]);
  376.  
  377.         /* Search the cache for the character */
  378.  
  379.         for (ppfcrec = &fccache[fcrec.hash % fcsize];
  380.              pfcrec = *ppfcrec, pfcrec != NULL;
  381.              ppfcrec = &pfcrec->chain)
  382.             if (pfcrec->hash == fcrec.hash &&
  383.                 pfcrec->dref == fcrec.dref &&
  384.                 pfcrec->nref == fcrec.nref &&
  385.                 pfcrec->matrix[0] == fcrec.matrix[0] &&
  386.                 pfcrec->matrix[1] == fcrec.matrix[1] &&
  387.                 pfcrec->matrix[2] == fcrec.matrix[2] &&
  388.                 pfcrec->matrix[3] == fcrec.matrix[3] &&
  389.                 pfcrec->id == fcrec.id)
  390.                 goto incache;
  391.  
  392.         /* Not in the cache; look up the build data.  Type 1 uses external
  393.          * data as we can't recurse, whereas type 3 uses local data */
  394.  
  395. nocache:
  396.         if (iflag == 0)
  397.         {   if (!dictget(font.value.vref, &charname[charfonttype],
  398.                                           &token, 0))
  399.                 error(errinvalidfont);
  400.             ftype = token.value.ival;
  401.             if (ftype == 1)
  402.                 initbuild(font.value.vref);
  403.             else
  404.             {   if (!dictget(font.value.vref, &charname[charbuildchar],
  405.                                               &bproc, 0))
  406.                     error(errinvalidfont);
  407.             }
  408.             iflag = 1;
  409.         }
  410.  
  411.         /* Build the character.  Push the interpreter state; save the
  412.          * graphics state and set up the new ctm.  Type 1 executes the
  413.          * character string, whereas type 3 interprets the build proc */
  414.  
  415.         nest = opernest;
  416.         pushint();
  417.         istate.flags = intchar;
  418.         istate.type = type;
  419.         istate.pfcrec = &fcrec;
  420.         gsave();
  421.         gstate.pathend = gstate.pathbeg;
  422.         memcpy((char *) gstate.ctm, (char *) newctm, sizeof newctm);
  423.         gstate.linecap = 0;
  424.         gstate.linejoin = 0;
  425.         gstate.mitrelimit = 10.0;
  426.         gstate.mitresin = 0.198997;
  427.         gstate.dashoffset = 0.0;
  428.         gstate.dasharray.length = 0;
  429.  
  430.         if (ftype == 1)
  431.             buildchar(schar);
  432.         else
  433.         {   gstate.flatness = 1.0;
  434.             gstate.linewidth = 1.0;
  435.             if (opernest + 2 > operstacksize) error(errstackoverflow);
  436.             operstack[opernest++] = font;
  437.             token.type = typeint;
  438.             token.flags = 0;
  439.             token.length = 0;
  440.             token.value.ival = schar;
  441.             operstack[opernest++] = token;
  442.             interpret(&bproc);
  443.         }
  444.  
  445.         grest();
  446.         pfcrec = istate.pfcrec;
  447.         popint();
  448.         if (opernest > nest) error(errstackoverflow);
  449.         if (opernest < nest) error(errstackunderflow);
  450.     
  451.         /* Increment the cache record usage count.  If the character is in
  452.          * the cache image it onto the page.  Add the width to the current
  453.          * point */
  454. incache:
  455.         pfcrec->count++;
  456.         if (type == 3 && pfcrec->reclen != 0)
  457.             cacheimage(pfcrec, &fpoint);
  458.         cpoint.x += pfcrec->width.x;
  459.         cpoint.y += pfcrec->width.y;
  460.  
  461.         /* Adjust the width */
  462.  
  463.         if (type == 3 && width != NULL)
  464.         {   if (schar == wchar)
  465.             {   cpoint.x += width[0].x;
  466.                 cpoint.y += width[0].y;
  467.             }
  468.             cpoint.x += width[1].x;
  469.             cpoint.y += width[1].y;
  470.         }
  471.  
  472.         /* Update the current point */
  473.  
  474.         if (type != 2)
  475.         {   cpoint.type = ptmove;
  476.             if (gstate.pathbeg == gstate.pathend ||
  477.                 patharray[gstate.pathend - 1].type != ptmove)
  478.                 checkpathsize(gstate.pathend + 1);
  479.             else
  480.                 gstate.pathend--;
  481.             patharray[gstate.pathend++] = cpoint;
  482.         }
  483.  
  484.         /* Call the kerning proc */
  485.  
  486.         if (kproc != NULL && length != 0)
  487.         {   if (opernest + 2 > operstacksize) error(errstackoverflow);
  488.             nest = opernest;
  489.             token.type = typeint;
  490.             token.flags = 0;
  491.             token.length = 0;
  492.             token.value.ival = schar;
  493.             operstack[opernest++] = token;
  494.             token.value.ival = *((unsigned char *) sptr);
  495.             operstack[opernest++] = token;
  496.             pushint();
  497.             interpret(kproc);
  498.             popint();
  499.             if (opernest > nest) error(errstackoverflow);
  500.             if (opernest < nest) error(errstackunderflow);
  501.         }
  502.     }
  503.  
  504.     /* For stringwidth return the width */
  505.  
  506.     if (type == 2)
  507.         *width = cpoint;
  508.  
  509.     flushlevel(lev);
  510. }
  511.  
  512. /*  Append the character path to the path of the saved graphics state */
  513.  
  514. void charpath(void)
  515. {   struct gstate *pgstate;
  516.     struct point *ppoint1, *ppoint2;
  517.     int pathlen, len, gap, snest;
  518.  
  519.     /* Locate the graphics state we saved before beginning the build proc */
  520.  
  521.     snest = istate.gbase;
  522.     pgstate = &gstack[snest];
  523.  
  524.     /* Shuffle all the newer paths up to make room */
  525.  
  526.     len = gstate.pathend - pgstate->pathend;
  527.     gap = pathlen = gstate.pathend - gstate.pathbeg;
  528.     if (patharray[pgstate->pathend - 1].type == ptmove) gap--;
  529.     checkpathsize(gstate.pathend + gap);
  530.     ppoint2 = &patharray[gstate.pathend];
  531.     ppoint1 = ppoint2 + gap;
  532.     while (len--) *--ppoint1 = *--ppoint2;
  533.  
  534.     /* Adjust the pointers to the paths we have moved */
  535.  
  536.     pgstate->pathend += gap;
  537.     while (++snest < gnest)
  538.     {    pgstate++;
  539.          pgstate->clipbeg += gap;
  540.          pgstate->pathbeg += gap;
  541.          pgstate->pathend += gap;
  542.     }
  543.     gstate.clipbeg += gap;
  544.     gstate.pathbeg += gap;
  545.     gstate.pathend = gstate.pathbeg;
  546.  
  547.     /* Copy the path */
  548.  
  549.     ppoint1 -= pathlen;
  550.     ppoint2 = &patharray[gstate.pathbeg];
  551.     while (pathlen--) *ppoint1++ = *ppoint2++;
  552. }
  553.  
  554. /* Set character width */
  555.  
  556. void setcharwidth(struct point *width)
  557. {   if (!(istate.flags & intchar)) error(errundefined);
  558.     istate.pfcrec->width = *width;
  559. }
  560.  
  561. /* Set cache device */
  562.  
  563. void setcachedevice(struct point *ll, struct point *ur, int ftype)
  564. {   struct fcrec *pfcrec, *pfcnxt, **ppfcrec;
  565.     float llx, lly, urx, ury;
  566.     int reclen, length, xbytes, xsize, ysize, fclim;
  567.  
  568.     /* Calculate the bitmap dimensions, check cache limit */
  569.  
  570.     llx = floor(ll->x);
  571.     lly = floor(ll->y);
  572.     urx = floor(ur->x - llx) + 1.0;
  573.     ury = floor(ur->y - lly) + 1.0;
  574.     if (fabs(llx) > 10000.0 || urx > 10000.0) return;
  575.     if (fabs(lly) > 10000.0 || ury > 10000.0) return;
  576.     xsize = urx;
  577.     ysize = ury;
  578.     xbytes = (xsize + 7) >> 3;
  579.     length = xbytes * ysize;
  580.     if (length > fclimit) return;
  581.  
  582.     /* For type 3 fonts we must ensure there is sufficient space for all
  583.      * the simultaneously active cache records; so we limit the record
  584.      * length to one third of the total length, and set the limit for the
  585.      * next level to one third too (allowing for fragmentation).  For type
  586.      * 1 fonts we can use the full length as there is no recursion */
  587.  
  588.     reclen =
  589.        (sizeof (struct fcrec) + length + (mcalign - 1)) & ~(mcalign - 1);
  590.     fclim = istate.fclim;
  591.     if (ftype == 3) fclim /= 3;
  592.     if (reclen > fclim) return;
  593.     if (ftype == 1) fclim = 0;
  594.     istate.fclim = fclim;
  595.  
  596.     /* Find a free cache slot.  Halve the usage counts as we go; free the
  597.      * records when they become empty, joining adjacent free records */
  598.  
  599.     for (;;)
  600.     {   if (fcptr == fcend) fcptr = fcbeg;
  601.         pfcrec = fcptr;
  602.         for (;;)
  603.         {   if (fcptr->count == 1)
  604.             {   ppfcrec = &fccache[fcptr->hash % fcsize];
  605.                 while (*ppfcrec != fcptr) ppfcrec = &((*ppfcrec)->chain);
  606.                 *ppfcrec = fcptr->chain;
  607.                 pfcnxt = (struct fcrec *) ((char *) fcptr + fcptr->reclen);
  608.                 if (pfcnxt != fcend && pfcnxt->count == 0)
  609.                     fcptr->reclen += pfcnxt->reclen;
  610.             }
  611.             if (fcptr->count != -1) fcptr->count >>= 1;
  612.             if (fcptr->count == 0 && fcptr != pfcrec)
  613.                 pfcrec->reclen += fcptr->reclen;
  614.             fcptr = (struct fcrec *) ((char *) fcptr + fcptr->reclen);
  615.             if (fcptr == fcend) break;
  616.             if (fcptr->count != 0 && fcptr->count != 1) break;
  617.             if (pfcrec->count != 0) break;
  618.             if (pfcrec->reclen >= reclen) break;
  619.         }
  620.         if (pfcrec->count == 0 && pfcrec->reclen >= reclen) break;
  621.     }
  622.  
  623.     /* If the record is large enough split it */
  624.  
  625.     if (pfcrec->reclen - reclen > sizeof (struct fcrec))
  626.     {   fcptr = (struct fcrec *) ((char *) pfcrec + reclen);
  627.         fcptr->count = 0;
  628.         fcptr->reclen = pfcrec->reclen - reclen;
  629.         pfcrec->reclen = reclen;
  630.     }
  631.  
  632.     /* Set up the cache record, adjust the ctm */
  633.  
  634.     ppfcrec = &fccache[istate.pfcrec->hash % fcsize];
  635.     pfcrec->chain = *ppfcrec;
  636.     *ppfcrec = pfcrec;
  637.     pfcrec->count = -1;
  638.     pfcrec->dref = istate.pfcrec->dref;
  639.     pfcrec->nref = istate.pfcrec->nref;
  640.     pfcrec->width = istate.pfcrec->width;
  641.     pfcrec->matrix[0] = istate.pfcrec->matrix[0];
  642.     pfcrec->matrix[1] = istate.pfcrec->matrix[1];
  643.     pfcrec->matrix[2] = istate.pfcrec->matrix[2];
  644.     pfcrec->matrix[3] = istate.pfcrec->matrix[3];
  645.     pfcrec->len = length;
  646.     pfcrec->hash = istate.pfcrec->hash;
  647.     pfcrec->id = istate.pfcrec->id;
  648.     pfcrec->xbytes = xbytes;
  649.     pfcrec->xsize = xsize;
  650.     pfcrec->ysize = ysize;
  651.     pfcrec->xoffset = llx;
  652.     pfcrec->yoffset = lly;
  653.     istate.pfcrec = pfcrec;
  654.     gstate.ctm[4] = -llx;
  655.     gstate.ctm[5] = -lly;
  656.  
  657.     /* Install the cache device */
  658.  
  659.     gstate.cacheflag = 1;
  660.     gstate.clipflag = 0;
  661.     gstate.gray = 0.0;
  662.     gstate.shade[0] = 0.0;
  663.     gstate.shadeok = 1;
  664.     screenok = 0;
  665.     gstate.dev.buf[0] = (char *) (pfcrec + 1);
  666.     gstate.dev.len = length;
  667.     gstate.dev.depth = 1;
  668.     gstate.dev.xbytes = pfcrec->xbytes;
  669.     gstate.dev.xsize = pfcrec->xsize;
  670.     gstate.dev.ysize = pfcrec->ysize;
  671.     gstate.dev.ybase = 0;
  672.     gstate.dev.yheight = pfcrec->ysize;
  673.     memset(gstate.dev.buf[0], 0, length);
  674. }
  675.  
  676. /* Get cache status */
  677.  
  678. void cachestatus(int *status)
  679. {   struct fmrec *pfmrec;
  680.     struct fcrec *pfcrec;
  681.     int count, length, i;
  682.     count = 0;
  683.     pfmrec = &fmcache[0];
  684.     i = fmsize;
  685.     while (i--)
  686.     {   if (pfmrec->id != 0) count++;
  687.         pfmrec++;
  688.     }
  689.     status[2] = count;
  690.     status[3] = fmsize;
  691.     count = 0;
  692.     length = 0;
  693.     if (fclen == 0)
  694.         status[1] = status[5] = 0;
  695.     else
  696.     {   pfcrec = fcbeg;
  697.         while (pfcrec != fcend)
  698.         {   if (pfcrec->count != 0)
  699.             {   count++;
  700.                 length += pfcrec->reclen;
  701.             }
  702.             pfcrec = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  703.         }
  704.         status[1] = fclen;
  705.         status[5] = fclen / sizeof (struct fcrec) - 1;
  706.     }
  707.     status[0] = length;
  708.     status[4] = count;
  709.     status[6] = fclimit;
  710. }
  711.  
  712. /* Set null device */
  713.  
  714. void nulldevice(void)
  715. {   gstate.dev.depth = 0;
  716.     gstate.dev.len = 0;
  717.     gstate.dev.xoff = 0;
  718.     gstate.dev.yoff = 0;
  719.     gstate.dev.xbytes = 0;
  720.     gstate.dev.xsize = 0;
  721.     gstate.dev.ysize = 0;
  722.     gstate.dev.ybase = 0;
  723.     gstate.dev.yheight = 0;
  724.     gstate.dev.xden = 72;
  725.     gstate.dev.yden = 72;
  726.     gstate.dev.ydir = 1;
  727.     gstate.clipflag = 0;
  728.     gstate.cacheflag = 0;
  729.     gstate.nullflag = 0;
  730.     cliplength(0);
  731.     halfok = gstacksize + 1;
  732.     initctm(gstate.ctm);
  733. }
  734.  
  735. /* Image the character data from the cache onto the page */
  736.  
  737. void cacheimage(struct fcrec *pfcrec, struct point *point)
  738. {   struct point *ppoint;
  739.     struct line *pline;
  740.     int xpos1, ypos1;
  741.     int x1, x2, y1, y2, xx;
  742.     int count, cdir;
  743.  
  744.     setupfill();
  745.  
  746.     /* Locate the image bounds */
  747.  
  748.     if (point->x < -1000.0 || point->x > 31000.0) return;
  749.     if (point->y < -1000.0 || point->y > 31000.0) return;
  750.  
  751.     xpos1 = (int) point->x + pfcrec->xoffset;
  752.     ypos1 = (int) point->y + pfcrec->yoffset;
  753.     y1 = ypos1;
  754.     y2 = ypos1 + pfcrec->ysize;
  755.     if (y1 < gstate.dev.ybase)
  756.         y1 = gstate.dev.ybase;
  757.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  758.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  759.     if (y1 == y2) return;
  760.  
  761.     /* If there is no clip path we always can do a fast image */
  762.  
  763.     if (!gstate.clipflag)
  764.         cachefast(pfcrec, xpos1, ypos1, y1, y2);
  765.  
  766.     /* Otherwise we must see if the image is within the clip path */
  767.  
  768.     else
  769.     {
  770.  
  771.         /* Set up the clip lines.   We clip them, using the minimum and
  772.          * maximum y values from the image */
  773.  
  774.         ymax = ylwb = y1 * 256.0;
  775.         ymin = yupb = y2 * 256.0;
  776.         lineend = 0;
  777.         count = gstate.pathbeg - gstate.clipbeg;
  778.         ppoint = &patharray[gstate.clipbeg];
  779.         while (count--)
  780.         {   if (ppoint->type != ptmove) fillline(ppoint - 1, 1, 0);
  781.             ppoint++;
  782.         }
  783.         if (lineend == 0) return;
  784.  
  785.         /* See if any of the clip lines intersect the image */
  786.  
  787.         x1 = xpos1 << 16;
  788.         x2 = (xpos1 + pfcrec->xsize) << 16;
  789.         count = lineend;
  790.         pline = &linearray[0];
  791.         cdir = 0;
  792.         while (count)
  793.         {   if (pline->y1 == y1 && pline->y2 != y1 && pline->xx < x1)
  794.                 cdir += pline->cdir;
  795.             xx = pline->xx + pline->d1 + pline->d2;
  796.             if (pline->y2 > pline->y1 + 1)
  797.                 xx +=  (pline->y2 - pline->y1 - 1) * pline->dx;
  798.             if (xx < x1 && pline->xx >= x2) break;
  799.             if (pline->xx < x1 && xx >= x2) break;
  800.             if (pline->xx >= x1 && pline->xx < x2) break;
  801.             if (xx >= x1 && xx < x2) break;
  802.             pline++;
  803.             count--;
  804.         }
  805.  
  806.         /* No lines intersect: either entirely visible or invisible */
  807.  
  808.         if (count == 0)
  809.         {   if (cdir == 0) return;
  810.             cachefast(pfcrec, xpos1, ypos1, y1, y2);
  811.         }
  812.  
  813.         /* If any lines intersect we must do a slow image */
  814.  
  815.         else
  816.             cacheslow(pfcrec, xpos1, ypos1, y1, y2);
  817.     }
  818.  
  819.     flushlpage(y1, y2);
  820. }
  821.  
  822. /* Slow image the character cache data */
  823.  
  824. void cacheslow(struct fcrec *pfcrec, int xpos1, int ypos1, int yy, int y2)
  825. {   struct line *pline, **ppline;
  826.     struct halfscreen *hscreen;
  827.     struct halftone *htone;
  828.     unsigned char *cbuf, *cbeg, *cptr; /* cache buffer row base, pointer */
  829.     char *dptr1, *dptr2;        /* device buffer pointers */
  830.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  831.     int count;                  /* counter */
  832.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  833.     int x1, x2, xp, xx;         /* current, previous x position range */
  834.     int cdir;                   /* clip direction counter */
  835.     int poff;                   /* offset of line from page */
  836.     int xmod, hxsize;           /* position modulo halftone screen */
  837.     int mask1, mask2;           /* bit masks for first and last bytes */
  838.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  839.     int s1, s2;                 /* segment to draw */
  840.     int xshf, xbeg, ibyte, ilast;
  841.     int xpos2;
  842.     int plane;
  843.  
  844.     /* Set up the y buckets */
  845.  
  846.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  847.  
  848.     /* Fill the area.  Start at the lowest scan line in the path and loo
  849.      * until we reach the highest */
  850.  
  851.     active = discard = sort = 0;
  852.     xshf = xpos1 & 7;
  853.     xbeg = (xpos1 < 0) ? ~((~xpos1) >> 3) : xpos1 >> 3;
  854.     xpos2 = xpos1 + pfcrec->xsize;
  855.     cbuf = (char *) (pfcrec + 1) + (yy - ypos1) * pfcrec->xbytes;
  856.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  857.  
  858.     while (yy < y2)
  859.     {
  860.         /* Add all the new lines */
  861.  
  862.         pline = ybucket[yy - gstate.dev.ybase];
  863.         ybucket[yy - gstate.dev.ybase] = NULL;
  864.         while (pline)
  865.         {   lineptr[active++] = pline;
  866.             pline = pline->chain;
  867.             sort++;
  868.         }
  869.  
  870.         /* If we have any lines out of order or (new, being discarded) then
  871.          * we Shell sort the lines according to their current x coordinates.
  872.          * Any previously finished lines have large x coordinates so will be
  873.          * moved to the end of the array where they are discarded */
  874.  
  875.         sort += discard;
  876.         if (sort != 0)
  877.         {   count = active;
  878.             for (;;)
  879.             {   count = count / 3 + 1;
  880.                 for (x1 = count; x1 < active; x1++)
  881.                     for (x2 = x1 - count;
  882.                          x2 >= 0 &&
  883.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  884.                          x2 -= count)
  885.                     {   pline = lineptr[x2];
  886.                         lineptr[x2] = lineptr[x2 + count];
  887.                         lineptr[x2 + count] = pline;
  888.                     }
  889.                 if (count == 1) break;
  890.             }
  891.             active -= discard;
  892.             discard = sort = 0;
  893.         }
  894.  
  895.         /* Scan convert the scan line */
  896.  
  897.         count = active;
  898.         cdir = 0;
  899.         ppline = &lineptr[0];
  900.         xp = -32767;
  901.  
  902.         while (count--)
  903.         {   pline = *ppline++;
  904.             x1 = pline->xx >> 16;
  905.  
  906.             /* At the end of the line (or if it is horizontal), use the
  907.              * special value of the x increment.  Flag it to be discarded.
  908.              * Draw only its width */
  909.  
  910.             if (yy == pline->y2)
  911.             {   pline->xx += pline->d2;
  912.                 x2 = pline->xx >> 16;
  913.                 pline->xx = 0x7fffffff;
  914.                 discard++;
  915.                 if (x2 < x1)
  916.                 {   xx = x1;
  917.                     x1 = x2;
  918.                     x2 = xx;
  919.                 }
  920.                 if (cdir == 0)
  921.                 {   s1 = x1;
  922.                     s2 = x2;
  923.                 }
  924.                 else
  925.                 {   if (x1 < s1) s1 = x1;
  926.                     if (x2 > s2) s2 = x2;
  927.                     continue;
  928.                 }
  929.             }
  930.  
  931.             /* At the beginning of the line, use the special value of the x
  932.              * increment, otherwise add the gradient to its current x
  933.              * coordinate.  We have to draw both the lines widths and the
  934.              * area enclosed.  For left edges we start drawing at the left
  935.              * of the line and draw the width too; for right edges we stop
  936.              * drawing at the right of the line. For interior lines we draw
  937.              * the line width (as it may not be interior higher up in the
  938.              * pixel */
  939.  
  940.             else
  941.             {   if      (yy == pline->y1)
  942.                     pline->xx += pline->d1;  /* Beginning */
  943.                 else
  944.                     pline->xx += pline->dx;  /* Middle */
  945.                 x2 = pline->xx >> 16;
  946.                 if (x2 < xp) sort++;
  947.                 xp = x2;
  948.                 if (x2 < x1)
  949.                 {   xx = x1;
  950.                     x1 = x2;
  951.                     x2 = xx;
  952.                 }
  953.                 if      (cdir == 0)          /* Left edge */
  954.                 {   cdir += pline->cdir;
  955.                     s1 = x1;
  956.                     s2 = x2;
  957.                     continue;
  958.                 }
  959.                 if (x1 < s1) s1 = x1;        /* Right edge, or ... */
  960.                 if (x2 > s2) s2 = x2;
  961.                 cdir += pline->cdir;
  962.                 if      (cdir != 0)          /* Interior */
  963.                     continue;
  964.             }
  965.             s2++;
  966.  
  967.             /* Draw from s1 to s2 */
  968.  
  969.             if (s1 < xpos1) s1 = xpos1;
  970.             if (s2 > xpos2) s2 = xpos2;
  971.             if (s1 < 0) s1 = 0;
  972.             if (s2 > gstate.dev.xsize) s2 = gstate.dev.xsize;
  973.             if (s1 >= s2) continue;
  974.             xbyt1 = s1 >> 3;
  975.             xbyt2 = (s2 - 1) >> 3;
  976.             mask1 =  0xff >> (s1 & 7);
  977.             mask2 = ~0xff >> (((s2 - 1) & 7) + 1);
  978.             cbeg = cbuf + xbyt1 - xbeg;
  979.  
  980.             /* Loop through the bit planes */
  981.  
  982.             hscreen = &halfscreen[0];
  983.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  984.             {   htone = hscreen->halftone;
  985.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  986.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  987.                 cptr = cbeg;
  988.                 ilast = 0;
  989.                 if (xbyt1 > xbeg) ilast = *(cptr - 1) << 8;
  990.  
  991.                 /* Optimise black or white */
  992.  
  993.                 if      (hscreen->num == 0)
  994.                 {   if (dptr1 == dptr2)
  995.                     {   mask1 &= mask2;
  996.                         *dptr1 |= (((ilast | *cptr) >> xshf) & mask1);
  997.                     }
  998.                     else
  999.                     {   *dptr1++ |=  (((ilast | *cptr) >> xshf) & mask1);
  1000.                         ilast = *cptr++ << 8;
  1001.                         while (dptr1 != dptr2)
  1002.                         {   *dptr1++ |=  ((ilast | *cptr) >> xshf);
  1003.                             ilast = *cptr++ << 8;
  1004.                         }
  1005.                         *dptr1 |=  (((ilast | *cptr) >> xshf) & mask2);
  1006.                     }
  1007.                 }
  1008.                 else if (hscreen->num == htone->area)
  1009.                 {   if (dptr1 == dptr2)
  1010.                     {   mask1 &= mask2;
  1011.                         *dptr1 &= ~(((ilast | *cptr) >> xshf) & mask1);
  1012.                     }
  1013.                     else
  1014.                     {   *dptr1++ &= ~(((ilast | *cptr) >> xshf) & mask1);
  1015.                         ilast = *cptr++ << 8;
  1016.                         while (dptr1 != dptr2)
  1017.                         {   *dptr1++ &= ~((ilast | *cptr) >> xshf);
  1018.                             ilast = *cptr++ << 8;
  1019.                         }
  1020.                         *dptr1 &= ~(((ilast | *cptr) >> xshf) & mask2);
  1021.                     }
  1022.                 }
  1023.  
  1024.                 /* The general case needs a halftone screen */
  1025.  
  1026.                 else
  1027.                 {   xmod = xbyt1 % htone->xsize;
  1028.                     hbeg = hscreen->ptr +
  1029.                         (yy % htone->ysize) * htone->xsize;
  1030.                     hptr = hbeg + xmod;
  1031.                     hxsize = htone->xsize;
  1032.                     if (dptr1 == dptr2)
  1033.                     {   ibyte = ((ilast | *cptr) >> xshf) & mask1 & mask2;
  1034.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1035.                     }
  1036.                     else
  1037.                     {   ibyte = ((ilast | *cptr) >> xshf) & mask1;
  1038.                         ilast = *cptr++ << 8;
  1039.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1040.                         dptr1++;
  1041.                         hptr++;
  1042.                         for (;;)
  1043.                         {   xmod++;
  1044.                             if (xmod == hxsize)
  1045.                             {   xmod = 0;
  1046.                                 hptr = hbeg;
  1047.                             }
  1048.                             if (dptr1 == dptr2) break;
  1049.                             ibyte = (ilast | *cptr) >> xshf;
  1050.                             ilast = *cptr++ << 8;
  1051.                             *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1052.                             dptr1++;
  1053.                             hptr++;
  1054.                         }
  1055.                         ibyte = ((ilast | *cptr) >> xshf) & mask2;
  1056.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1057.                     }
  1058.                 }
  1059.             }
  1060.         }
  1061.  
  1062.         /* Continue with the next scan line */
  1063.  
  1064.         cbuf += pfcrec->xbytes;
  1065.         poff += gstate.dev.xbytes;
  1066.         yy++;
  1067.     }
  1068.  
  1069.     ybflag = 0;
  1070. }
  1071.  
  1072. /* Fast image the character cache data */
  1073.  
  1074. void cachefast(struct fcrec *pfcrec, int xpos1, int ypos1, int y1, int y2)
  1075. {   struct halfscreen *hscreen;
  1076.     struct halftone *htone;
  1077.     unsigned char *cbuf, *cbeg, *cptr; /* cache buffer row base, pointer */
  1078.     char *dbeg, *dptr1, *dptr2; /* device buffer row base, pointers */
  1079.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1080.     int xbeg, xmod, ymod, hxsize;
  1081.     int xshf, ibyte, ilast;
  1082.     int x1, x2, xx, yy;
  1083.     int plane;
  1084.  
  1085.     cbuf = (char *) (pfcrec + 1) + pfcrec->xbytes * (y1 - ypos1);
  1086.     xshf = xpos1 & 7;
  1087.     x1 = (xpos1 < 0) ? ~((~xpos1) >> 3) : xpos1 >> 3;
  1088.     x2 = x1 + pfcrec->xbytes;
  1089.     if (x1 < 0)
  1090.     {   cbuf -= x1;
  1091.         x1 = 0;
  1092.     }
  1093.     if (x2 > gstate.dev.xbytes)
  1094.         x2 = gstate.dev.xbytes;
  1095.     if (x1 >= x2) return;
  1096.     xx = x2 - x1;
  1097.  
  1098.     /* Loop through the bit planes */
  1099.  
  1100.     hscreen = &halfscreen[0];
  1101.     for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1102.     {   htone = hscreen->halftone;
  1103.         cbeg = cbuf;
  1104.         dbeg = gstate.dev.buf[plane] +
  1105.             (y1 - gstate.dev.ybase) * gstate.dev.xbytes + x1;
  1106.         yy = y1;
  1107.  
  1108.         /* Optimise black or white */
  1109.  
  1110.         if      (hscreen->num == 0)
  1111.         {   while (yy < y2)
  1112.             {   dptr1 = dbeg;
  1113.                 dptr2 = dbeg + xx;
  1114.                 cptr = cbeg;
  1115.  
  1116.                 ilast = 0;
  1117.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1118.  
  1119.                 for (;;)
  1120.                 {   *dptr1++ |=  ((ilast | *cptr) >> xshf);
  1121.                     ilast = *cptr++ << 8;
  1122.                     if (dptr1 == dptr2) break;
  1123.                 }
  1124.  
  1125.                 if (x2 < gstate.dev.xbytes)
  1126.                     *dptr1   |=  ( ilast          >> xshf);
  1127.                 cbeg += pfcrec->xbytes;
  1128.                 dbeg += gstate.dev.xbytes;
  1129.                 yy++;
  1130.             }
  1131.         }
  1132.         else if (hscreen->num == htone->area)
  1133.         {   while (yy < y2)
  1134.             {   dptr1 = dbeg;
  1135.                 dptr2 = dbeg + xx;
  1136.                 cptr = cbeg;
  1137.  
  1138.                 ilast = 0;
  1139.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1140.  
  1141.                 for (;;)
  1142.                 {   *dptr1++ &= ~((ilast | *cptr) >> xshf);
  1143.                     ilast = *cptr++ << 8;
  1144.                     if (dptr1 == dptr2) break;
  1145.                 }
  1146.  
  1147.                 if (x2 < gstate.dev.xbytes)
  1148.                     *dptr1   &= ~( ilast          >> xshf);
  1149.                 cbeg += pfcrec->xbytes;
  1150.                 dbeg += gstate.dev.xbytes;
  1151.                 yy++;
  1152.             }
  1153.         }
  1154.  
  1155.         /* The general case needs a halftone screen */
  1156.  
  1157.         else
  1158.         {   hxsize = htone->xsize;
  1159.             xbeg = x1 % htone->xsize;
  1160.             ymod = yy % htone->ysize;
  1161.             hbeg = hscreen->ptr + ymod * hxsize;
  1162.             while (yy < y2)
  1163.             {   dptr1 = dbeg;
  1164.                 dptr2 = dbeg + xx;
  1165.                 cptr = cbeg;
  1166.                 xmod = xbeg;
  1167.                 hptr = hbeg + xbeg;
  1168.  
  1169.                 ilast = 0;
  1170.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1171.  
  1172.                 for (;;)
  1173.                 {   ibyte = (ilast | *cptr) >> xshf;
  1174.                     *dptr1 = (*dptr1 & ~ibyte) | (*hptr++ &  ibyte);
  1175.                     dptr1++;
  1176.                     ilast = *cptr++ << 8;
  1177.                     xmod++;
  1178.                     if (xmod == hxsize)
  1179.                     {   xmod = 0;
  1180.                         hptr = hbeg;
  1181.                     }
  1182.                     if (dptr1 == dptr2) break;
  1183.                 }
  1184.  
  1185.                 if (x2 < gstate.dev.xbytes)
  1186.                 {   ibyte =  ilast          >> xshf;
  1187.                     *dptr1 = (*dptr1 & ~ibyte) | (*hptr   &  ibyte);
  1188.                 }
  1189.                 cbeg += pfcrec->xbytes;
  1190.                 dbeg += gstate.dev.xbytes;
  1191.                 hbeg += hxsize;
  1192.                 ymod++;
  1193.                 if (ymod == htone->ysize)
  1194.                 {   ymod = 0;
  1195.                     hbeg = hscreen->ptr;
  1196.                 }
  1197.                 yy++;
  1198.             }
  1199.         }
  1200.     }
  1201. }
  1202.  
  1203. /* End of file "postchar.c" */
  1204.